package com.fxd.util;

import com.fxd.conn.JedisConnUtil;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.GeoRadiusParam;

import java.util.List;
import java.util.Map;

/**
 * 地图工具类
 */
@Slf4j
public class GeoHashUtil {

    private GeoHashUtil() {
    }

    /**
     * 单个添加
     *
     * @param key       主键，建议一个省对应一个key，或者更小范围，防止一个key空间过大
     * @param longitude 经度
     * @param latitude  纬度
     * @param location  存入地点名称
     * @return 是否添加成功
     */
    public static boolean geoAdd(String key, double longitude, double latitude, String location) {
        if (0 <= longitude && longitude <= 180 && 0 <= latitude && latitude <= 90) {
            Jedis jedis = JedisConnUtil.getJedis();
            return jedis.geoadd(key, longitude, latitude, location) > 0;
        } else {
            log.info("location:{}经纬度异常:{},{}", location, longitude, latitude);
        }
        return false;
    }

    /**
     * 批量新增
     *
     * @param key 主键
     * @param map Map对象，键为存入地点名称，值为GeoCoordinate对象
     * @return
     */
    public static boolean geoAdd(String key, Map<String, GeoCoordinate> map) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.geoadd(key, map) == map.size();
    }

    /**
     * @param key      主键
     * @param location 存入地点名称
     * @return 地点经纬度
     */
    public static List<GeoCoordinate> geoPos(String key, String location) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.geopos(key, location);
    }

    /**
     * @param key       主键
     * @param location1 地点1
     * @param location2 地点2
     * @return 相距距离，单位默认(KM)
     */
    public static double geoDist(String key, String location1, String location2) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.geodist(key, location1, location2, GeoUnit.KM);
    }

    /**
     * @param key       主键
     * @param location1 地点1
     * @param location2 地点2
     * @param geoUnit   单位
     * @return
     */
    public static double geoDist(String key, String location1, String location2, GeoUnit geoUnit) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.geodist(key, location1, location2, geoUnit);
    }

    /**
     * 获取单个地点的geoHash
     *
     * @param key      主键
     * @param location 地点
     * @return
     */
    public static String geoHash(String key, String location) {
        Jedis jedis = JedisConnUtil.getJedis();
        //该方法如果location不存在，会返回一个集合，元素值为null
        return jedis.geohash(key, location).get(0);
    }

    /**
     * 同时获取多个地点的geoHash
     *
     * @param key      主键
     * @param location 地点...
     * @return
     */
    public static List<String> geoHash(String key, String... location) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.geohash(key, location);
    }

    /**
     * 根据经纬度查找附近的地点
     *
     * @param key       主键
     * @param longitude 经度
     * @param latitude  纬度
     * @param distance  半径，单位默认(KM)
     * @return
     */
    public static List<GeoRadiusResponse> geoRadius(String key, double longitude, double latitude, double distance) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadius(key, longitude, latitude, distance, GeoUnit.KM);
    }

    /**
     * 根据经纬度查找附近的地点(指定单位)
     *
     * @param key       主键
     * @param longitude 经度
     * @param latitude  纬度
     * @param distance  半径
     * @param geoUnit   单位
     * @return
     */
    public static List<GeoRadiusResponse> geoRadius(String key, double longitude, double latitude, double distance, GeoUnit geoUnit) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadius(key, longitude, latitude, distance, geoUnit);
    }

    /**
     * 附加响应
     * withdist  将位置元素与中心之间的距离也一并返回，距离的单位和用户给定的范围单位保持一致
     * withcoord 将位置元素的经度和维度也一并返回
     * withhash 以 52 位有符号整数的形式，返回位置元素经过原始 geohash 编码的有序集合分值
     * asc 根据中心的位置，按照从近到远的方式返回位置元素
     * desc 根据中心的位置，按照从远到近的方式返回位置元素
     * count 返回条数
     *
     * @param key       主键
     * @param longitude 经度
     * @param latitude  纬度
     * @param distance  半径
     * @param geoUnit   单位
     * @param param     附加响应
     * @return
     */
    public static List<GeoRadiusResponse> geoRadius(String key, double longitude, double latitude, double distance, GeoUnit geoUnit, GeoRadiusParam param) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadius(key, longitude, latitude, distance, geoUnit, param);
    }

    /**
     * 根据地点查找附近的地点
     *
     * @param key      主键
     * @param location 地点
     * @param distance 半径，默认单位(KM)
     * @return
     */
    public static List<GeoRadiusResponse> geoRadiusByMember(String key, String location, double distance) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadiusByMember(key, location, distance, GeoUnit.KM);
    }

    /**
     * 根据地点查找附近的地点(带参数)
     *
     * @param key      主键
     * @param location 地点
     * @param distance 半径
     * @param geoUnit  单位
     * @param param    附加响应
     * @return
     */
    public static List<GeoRadiusResponse> geoRadiusByMember(String key, String location, double distance, GeoUnit geoUnit, GeoRadiusParam param) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadiusByMember(key, location, distance, geoUnit, param);
    }

    /**
     * 根据地点查找附近的地点(只读)
     *
     * @param key      主键
     * @param location 地点
     * @param distance 半径，默认单位(KM)
     * @return
     */
    public static List<GeoRadiusResponse> geoRadiusByMemberReadonly(String key, String location, double distance) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadiusByMemberReadonly(key, location, distance, GeoUnit.KM);
    }

    public static List<GeoRadiusResponse> geoRadiusByMemberReadonly(String key, String location, double distance, GeoUnit geoUnit, GeoRadiusParam param) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.georadiusByMemberReadonly(key, location, distance, geoUnit, param);
    }

}
